﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FatusoAction.Model;
using System.Configuration;
using System.Globalization;

namespace FatusoAction
{
    public class ProgramAction
    {
        public static void ExecutarComando(Comando comando, string parametros, List<string> opcoesComando)
        {
            int maxContadorTorrent = Convert.ToInt32(ConfigurationSettings.AppSettings["ContadorEpisodio"]);
            int maxContadorLegenda = Convert.ToInt32(ConfigurationSettings.AppSettings["ContadorLegenda"]);

            TipoVideo tipoVideo = TipoVideo.Serie;
            //if (comando == Comando.Episodio || comando == Comando.Legenda || comando == Comando.Serie) 
            //    tipoVideo = TipoVideo.Serie;
            if (comando == Comando.Filme || comando == Comando.FilmeLegenda || comando == Comando.LegendaFilme || comando == Comando.Filme) 
                tipoVideo = TipoVideo.Filme;

            switch (comando)
            {
                //Filmes e Séries
                case Comando.FilmeVideo:
                case Comando.Episodio:
                    ComandoEpisodioVideoFilme(parametros, maxContadorTorrent, tipoVideo, opcoesComando);
                    break;
                case Comando.Legenda:
                case Comando.FilmeLegenda:
                case Comando.LegendaFilme:
                    ComandoLegenda(parametros, maxContadorLegenda, tipoVideo, opcoesComando);
                    break;
                case Comando.Download:
                case Comando.Serie:
                case Comando.Filme:
                    ComandoSerieFilme(parametros, maxContadorLegenda, maxContadorTorrent, tipoVideo, opcoesComando);
                    break;


                //Outros
                case Comando.Sync:
                    ComandoSync(parametros);
                    break;
                default: 
                    break;
            }
        }


        #region [Comandos Principais]

        public static void ComandoEpisodioVideoFilme(string release, int maxContadorEpisodio, TipoVideo tipoVideo, List<string> opcoesComando)
        {
            if (tipoVideo == TipoVideo.Indefinido) tipoVideo = TipoVideo.Serie;
            string tipo = (tipoVideo == TipoVideo.Serie) ? "episódio" : "filme";
            LegendaIdioma legendaIdioma = VerificaOpcoesDoComando<LegendaIdioma>(ref opcoesComando);
            LegendaFonte legendaFonte = VerificaOpcoesDoComando<LegendaFonte>(ref opcoesComando);

            TituloModel tituloVerificado = VerificaRelease(release, tipoVideo, opcoesComando);

            try
            {
                Console.WriteLine("Procurando " + tipo + "...");
                List<EpisodioModel> episodios =
                    EpisodioAction.RecuperaEpisodio_KatPH(TipoVideo.Serie, tituloVerificado, maxContadorEpisodio);

                if (episodios.Count == 0) throw new Exception("Não foi encontrado nenhum " + tipo + " para este release.");
                else Console.WriteLine("Baixando " + tipo + "...");

                foreach (EpisodioModel episodio in episodios)
                {
                    EpisodioAction.DownloadEpisodio_KatPH(episodio, tipoVideo, tituloVerificado);
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public static void ComandoLegenda(string release, int maxContadorLegenda, TipoVideo tipoVideo, List<string> opcoesComando)
        {
            try
            {
                LegendaIdioma legendaIdioma = VerificaOpcoesDoComando<LegendaIdioma>(ref opcoesComando);
                LegendaFonte legendaFonte = VerificaOpcoesDoComando<LegendaFonte>(ref opcoesComando);

                TituloModel tituloVerificado = VerificaRelease(release, tipoVideo, opcoesComando);

                List<LegendaModel> legendas =
                    LegendaAction.RecuperaLegenda(tipoVideo, tituloVerificado, maxContadorLegenda, legendaIdioma, legendaFonte, false);

                if (legendas.Count == 0)
                {
                    Console.WriteLine(">Nao foram encontradas legendas para este release.");
                    return;
                }
                else Console.WriteLine(">Baixando Legendas...");

                foreach (LegendaModel legenda in legendas)
                {
                    LegendaAction.DownloadLegenda(legenda, tituloVerificado);
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public static void ComandoSerieFilme(string release, int maxContadorLegenda, int maxContadorTorrent, TipoVideo tipoVideo, List<string> opcoesComando)
        {
            DownloadSerieFilmePorComparacao(release, maxContadorLegenda, maxContadorTorrent, tipoVideo, opcoesComando);
        }

        #endregion


        #region [Métodos Privados]

        private static void DownloadSerieFilmePorTorrent(TituloModel titulo, int maxContadorLegenda, int maxContadorTorrent, TipoVideo tipoVideo, 
            LegendaIdioma idioma, LegendaFonte legendaFonte)
        {
            string tipo = (tipoVideo == TipoVideo.Serie) ? "episódio" : "filme";
            bool downloadLTV = legendaFonte == LegendaFonte.LTV || legendaFonte == LegendaFonte.Todos;
            bool downloadPNP = legendaFonte == LegendaFonte.PNP || legendaFonte == LegendaFonte.Todos;

            Console.WriteLine(">Procurando " + tipo + "...");
            List<EpisodioModel> episodios =
                EpisodioAction.RecuperaEpisodio(tipoVideo, titulo, maxContadorTorrent);
            if (episodios.Count == 0)
            {
                Console.WriteLine(">Não foi encontrado nenhum " + tipo + " para este release.");
                return;
            }

            List<LegendaModel> legendas = new List<LegendaModel>();
            Console.WriteLine(">Procurando legendas...");

            #region [Procura Legendas Idênticas - LTV]
            if (downloadLTV)
            {
                foreach (EpisodioModel episodioEncontrado in episodios)
                {
                    try
                    {
                        string releaseFiltro = FolderAndXMLAction.FiltraCaracteres(episodioEncontrado.Release, false);
                        TituloModel tituloPesquisa = new TituloModel(titulo.NomeFilmeOuSerie, titulo.AnoOuTagEpisodio, releaseFiltro);

                        legendas = LegendaAction.RecuperaLegenda(tipoVideo, tituloPesquisa, maxContadorLegenda, idioma, LegendaFonte.LTV, true);
                        if (legendas.Count > 0)
                        {
                            Console.WriteLine(">Baixando " + tipo + "...");
                            EpisodioAction.DownloadEpisodio(episodioEncontrado, tipoVideo, titulo);

                            Console.WriteLine(">Baixando legendas...");
                            foreach (LegendaModel legenda in legendas)
                            {
                                LegendaAction.DownloadLegenda(legenda, titulo);
                            }
                            break;
                        }
                    }
                    catch (Exception ex) { }
                }
            }
            #endregion

            #region [Procura Legendas Idênticas - PNP]
            if (downloadPNP)
            {
                if (legendas.Count == 0)
                {
                    foreach (EpisodioModel episodioEncontrado in episodios)
                    {
                        try
                        {
                            string releaseFiltro = FolderAndXMLAction.FiltraCaracteres(episodioEncontrado.Release, false);
                            TituloModel tituloPesquisa = new TituloModel(titulo.NomeFilmeOuSerie, titulo.AnoOuTagEpisodio, releaseFiltro);

                            legendas = LegendaAction.RecuperaLegenda(tipoVideo, tituloPesquisa, maxContadorLegenda, idioma, LegendaFonte.PNP, true);
                            if (legendas.Count > 0)
                            {
                                Console.WriteLine(">Baixando " + tipo + "...");
                                EpisodioAction.DownloadEpisodio(episodioEncontrado, tipoVideo, titulo);

                                Console.WriteLine(">Baixando legendas...");
                                foreach (LegendaModel legenda in legendas)
                                {
                                    LegendaAction.DownloadLegenda(legenda, titulo);
                                }
                                break;
                            }
                        }
                        catch (Exception ex) { }
                    }
                }
            }
            #endregion

            //Sem Legendas Encontradas
            if (legendas.Count == 0)
            {
                Console.WriteLine(">Não foram encontradas legendas idênticas para esse release.");
                Console.WriteLine(">Procurando outras legendas...");
                legendas = LegendaAction.RecuperaLegenda(tipoVideo, titulo, maxContadorLegenda, idioma, legendaFonte, true);
                if (legendas.Count == 0)
                    Console.WriteLine(">Não foram encontradas legendas para esse release.");

                try
                {
                    Console.WriteLine(">Baixando opções de " + tipo + "...");
                    foreach (EpisodioModel episodio in episodios)
                    {
                        EpisodioAction.DownloadEpisodio(episodio, tipoVideo, titulo);
                    }

                    if (legendas.Count > 0)
                    {
                        Console.WriteLine(">Baixando opções de legenda...");
                        foreach (LegendaModel legenda in legendas)
                        {
                            LegendaAction.DownloadLegenda(legenda, titulo);
                        }
                    }
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
        }

        private static void DownloadSerieFilmePorComparacao(string release, int maxContadorLegenda, int maxContadorTorrent, TipoVideo tipoVideo, List<string> opcoesComando)
        {
            if (opcoesComando == null) opcoesComando = new List<string>();
            LegendaIdioma legendaIdioma = VerificaOpcoesDoComando<LegendaIdioma>(ref opcoesComando);
            LegendaFonte legendaFonte = VerificaOpcoesDoComando<LegendaFonte>(ref opcoesComando);
            TituloModel tituloVerificado = VerificaRelease(release, tipoVideo, opcoesComando);

            if (tituloVerificado != null)
                DownloadSerieFilmePorTorrent(tituloVerificado, maxContadorLegenda, maxContadorTorrent, tipoVideo, legendaIdioma, legendaFonte);
        }

        private static void ComandoCriarEbook(string parametros)
        {
            try
            {
                EbookAction.CriarEbook(parametros);
                Console.WriteLine("Ebook criado com sucesso!");
            }
            catch (Exception ex)
            {
                Console.WriteLine("Erro: " + ex.Message);
            }
        }

        private static void ComandoCarona(string parametros)
        {
            string origem = String.Empty;
            string destino = String.Empty;
            DateTime data = DateTime.Today;
            try
            {
                List<string> parSplit = parametros.Split(' ').ToList();
                if (parSplit.Count < 3) throw new Exception("Parâmetros Inválidos.");

                foreach (string str in parSplit)
                {
                    string parametro = str.ToLower().Trim();
                    if (parametro == "de" || parametro == "para" || parametro == "data")
                    {
                        int index = parSplit.IndexOf(str);
                        if (parSplit[index + 1] != null && parSplit[index + 1] != String.Empty)
                        {
                            if (parametro == "de") origem = parSplit[index + 1];
                            if (parametro == "para") destino = parSplit[index + 1];
                            try
                            {
                                if (parametro == "data") data = DateTime.ParseExact(parSplit[index + 1], "dd/MM/yyyy", CultureInfo.InvariantCulture);
                            }
                            catch (Exception ex) {/*Logar Erro*/ }
                        }
                    }
                }

                List<CaronaModel> caronasEncontradas = CaronaAction.ListarCaronas(origem, destino, data, TipoCarona.Oferecimento);


                Console.WriteLine("Número de Caronas Encontradas: " + caronasEncontradas.Count);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Erro: " + ex.Message);
            }

        }

        private static void ComandoSync(string parametros)
        {
            SyncAction.SyncXML(parametros);
        }

        private static TituloModel VerificaRelease(string release, TipoVideo tipoVideo, List<string> opcoesComando)
        {
            string tipo = (tipoVideo == TipoVideo.Serie) ? "episódio" : "filme";
            TextInfo textInfo = new CultureInfo("en-US", false).TextInfo;
            release = textInfo.ToTitleCase(release.ToLower());
            
            //Dados para retorno
            string retornoNome = "";
            string retornoAnoOuTag = "";

            #region [Verificação da Existência da Série]
            if (tipoVideo == TipoVideo.Serie)
            {
                retornoAnoOuTag = FolderAndXMLAction.RecuperaTagEpisodio(release, true);
                if (string.IsNullOrEmpty(retornoAnoOuTag))
                {
                    Console.WriteLine(">Número do episódio não foi identificado.");
                    return null;
                }

                string name = FolderAndXMLAction.RecuperaNomeSerie(release);
                retornoNome = name;
                List<string> seriesPossiveis = FolderAndXMLAction.RecuperaSeriesPossiveis(release);
                if (seriesPossiveis.Count > 0)
                {
                    if (seriesPossiveis.Count == 1 && name.ToUpper().Trim() == seriesPossiveis[0].ToUpper().Trim())
                    {
                        retornoNome = textInfo.ToTitleCase(seriesPossiveis[0].ToLower());
                    }
                    else
                    {
                        int indexSerieSelecionada = -1;
                        Console.WriteLine(">Você quis dizer uma das séries abaixo?\n");
                        foreach (string serie in seriesPossiveis)
                        {
                            int numeroSerie = seriesPossiveis.IndexOf(serie) + 1;
                            Console.WriteLine("> [ " + numeroSerie.ToString("00") + " ] " + serie);
                        }

                        string indexStr = "";
                        Console.Write("\nDigite o número da série desejada, ou 0 para continuar: ");
                        for (int i = 0; i < 3; i++)
                        {
                            indexStr = Console.ReadLine();
                            try
                            {
                                indexSerieSelecionada = Convert.ToInt32(indexStr);
                                if (indexSerieSelecionada > seriesPossiveis.Count) throw new Exception();
                                break;
                            }
                            catch (Exception ex)
                            {
                                Console.Write("\nNúmero inválido. Por favor, digite o número da série desejada, ou 0 para continuar: ");
                            }
                        }
                        if (indexSerieSelecionada > 0)
                        {
                            indexSerieSelecionada--;
                            retornoNome = textInfo.ToTitleCase(seriesPossiveis[indexSerieSelecionada].ToLower());
                            
                        }
                        else if (indexSerieSelecionada < 0)
                            return null;
                    }
                }
            }
            #endregion

            #region [Verificação da Existência do Filme]
            if (tipoVideo == TipoVideo.Filme)
            {
                List<TituloModel> titulos = FilmeAction.VerificaTitulos(release);
                string tag = FolderAndXMLAction.RecuperaTagFilme(release, TipoRetornoTag.PosTag);
                if (titulos.Count > 0)
                {
                    int indexTituloSelecionado = -1;
                    Console.WriteLine(">Os seguintes filmes foram encontrados:\n");
                    foreach (TituloModel titulo in titulos)
                    {
                        int numeroFilme = titulos.IndexOf(titulo) + 1;
                        Console.WriteLine("> [ " + numeroFilme.ToString("00") + " ] " + titulo.ReleaseParentesis);
                    }

                    string indexStr = "";
                    Console.Write("\nPor favor, digite o número do filme desejado, ou 0 para continuar: ");
                    for (int i = 0; i < 3; i++)
                    {
                        indexStr = Console.ReadLine();
                        try
                        {
                            indexTituloSelecionado = Convert.ToInt32(indexStr);
                            if (indexTituloSelecionado > titulos.Count) throw new Exception();
                            break;
                        }
                        catch (Exception)
                        {
                            Console.WriteLine("Número inválido. Digite o número do filme desejado, ou 0 para continuar:");
                        }
                    }
                    if (indexTituloSelecionado > 0)
                    {
                        indexTituloSelecionado--;
                        retornoNome = titulos[indexTituloSelecionado].NomeFilmeOuSerie;
                        retornoAnoOuTag = titulos[indexTituloSelecionado].AnoOuTagEpisodio;
                    }
                    else if (indexTituloSelecionado < 0)
                        return null;
                }

            }
            #endregion

            TituloModel tituloRetorno = new TituloModel(retornoNome, retornoAnoOuTag);
            Console.Write("\nSelecionado: " + tituloRetorno.Release + "\n");

            foreach (string opcao in opcoesComando)
                tituloRetorno.Release += " " + opcao.ToUpper();

            return tituloRetorno;
        }

        private static T VerificaOpcoesDoComando<T>(ref List<string> opcoesComando)
        {
            if (typeof(T).IsEnum)
            {
                int indexExcluir = -1;
                T retorno = default(T);
                foreach (string opcao in opcoesComando)
                {
                    try
                    {
                        retorno = (T)Enum.Parse(typeof(T), opcao, true);
                        indexExcluir = opcoesComando.IndexOf(opcao);
                        break;
                    }
                    catch (Exception) { }
                }
                if (indexExcluir >= 0)
                    opcoesComando.RemoveAt(indexExcluir);
                return retorno;
            }
            return default(T);
        }
        #endregion
    }
}
